package com.zysc.processflow.common.maputil;

import java.util.ArrayList;
import java.util.List;

/**
 * 参考文献https://williamic.github.io/article/algorithm-polygonIntersection/
 *
 */

public class Helper {
    /**
     * 经纬度转XY坐标（厘米为单位）
     *
     * @param latLongList
     * @return
     */
    private static List<Point2D> loc2Point2D(LatLong origin, List<LatLong> latLongList) {
        ArrayList<Point2D> pointList = new ArrayList<>();//坐标
        for (int i = 0; i < latLongList.size(); i++) {
            Point2D point2D = loc2Point2D(origin, latLongList.get(i), i);
            pointList.add(point2D);
        }
        return pointList;
    }

    /**
     * 获取loc相对于origin的坐标
     */
    private static Point2D loc2Point2D(LatLong origin, LatLong loc, int pointIndex) {
        Point2D point2D = new Point2D(lon2cm(origin, loc), lat2cm(origin, loc), pointIndex);
        return point2D;
    }

    /**
     * 经度补偿
     *
     * @param latitude 纬度
     * @return
     */
    private static double longitude_scale(double latitude) {
        double cos = Math.cos(latitude * 3.14159265358979323846 / 180.0);
        if (cos < 0.01) {
            cos = 0.01;
        } else if (cos > 1.0) {
            cos = 1.0;
        }
        return cos;
    }

    /**
     * 经度差转距离（厘米）
     *
     * @param origin
     * @param loc
     * @return
     */
    private static double lon2cm(LatLong origin, LatLong loc) {
        double v = loc.getLongitude() - origin.getLongitude();//经度差
        double v1 = (89.83204953368922 / 1E7) / longitude_scale(origin.getLatitude());//对应的比例  XX°/m
        return  v / v1 * 100;//厘米
    }

    /**
     * 纬度差转距离（厘米）
     *
     * @param origin
     * @param loc
     * @return
     */
    private static double lat2cm(LatLong origin, LatLong loc) {
        double v = loc.getLatitude() - origin.getLatitude();//纬度差
        return v / (89.83204953368922 / 1E7) * 100;//厘米
    }
    /**
     * 判断点是否在边上
     *
     * @param lineList
     * @param targetPoint
     * @return
     */
    public static boolean isOnLine(List<Line2D> lineList, Point2D targetPoint) {
        for (int i = 0; i < lineList.size(); i++) {
            Line2D line = lineList.get(i);
            if (line.isIn(targetPoint)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取点到直线的距离，正值表示在startVector直线上方，负值表示在startVector直线下方
     *
     * @param startPoint
     * @param endPoint
     * @param targetPoint
     * @return
     */
    public static double getRealYDis(Point2D startPoint, Point2D endPoint, Point2D targetPoint) {
        Vector2D startVector = new Vector2D(endPoint.x - startPoint.x, endPoint.y - startPoint.y);
        Vector2D endVector = new Vector2D(targetPoint.x - startPoint.x, targetPoint.y - startPoint.y);
        double v = startVector.crossProduct(endVector);
        double dis = v / startVector.getLength();
        double angle = startVector.getAngle();
        if (angle >= -90 && angle < 90) {
            dis = dis;
        } else {
            dis = -dis;
        }
        return dis;
    }

    //点与直线x轴上的距离
    public static double getXDis(Point2D startPoint, Point2D endPoint, Point2D targetPoint) {
        Vector2D startVector = new Vector2D(endPoint.x - startPoint.x, endPoint.y - startPoint.y);
        Vector2D endVector = new Vector2D(targetPoint.x - startPoint.x, targetPoint.y - startPoint.y);
        double v = startVector.dotProduct(endVector);
        return v / startVector.getLength();
    }
    /**
     * 获取线段集合
     *
     * @param pointList
     * @return
     */
    private static List<Line2D> point2Line(List<Point2D> pointList) {
        //线段集合
        List<Line2D> lineList = new ArrayList<>();
        for (int i = 0; i < pointList.size(); i++) {
            Line2D line2D;
            if (i == pointList.size() - 1) {
                line2D = new Line2D(pointList.get(i), pointList.get(0), i);
            } else {
                line2D = new Line2D(pointList.get(i), pointList.get(i + 1), i);
            }
            lineList.add(line2D);
        }
        return lineList;
    }

    /**
     * 判断目标点是否在指定多边形内，适应全部多边形
     *
     * @param target
     * @param polygon
     * @return
     */
    public static boolean isInPolygon(Point2D target, List<Point2D> polygon) {
        int counter = 0;
        int i;
        double xinters;
        Point2D p1, p2;
        int pointCount = polygon.size();
        p1 = (Point2D) polygon.get(0);
        for (i = 1; i <= pointCount; i++) {
            p2 = polygon.get(i % pointCount);
            //校验点的Y大于线段端点的最小Y
            if (target.getY() > Math.min(p1.getY(), p2.getY()) && target.getY() <= Math.max(p1.getY(), p2.getY()))//校验点的Y小于线段端点的最大Y
            {
                if (target.getX() <= Math.max(p1.getX(), p2.getX()))//校验点的X小于等于线段端点的最大X(使用校验点的左射线判断).
                {
                    if (p1.getY() != p2.getY())//线段不平行于X轴
                    {
                        xinters = (target.getY() - p1.getY()) * (p2.getX() - p1.getX()) / (p2.getY() - p1.getY()) + p1.getX();
                        if (p1.getX() == p2.getX() || target.getX() <= xinters) {
                            counter++;
                        }
                    }
                }
            }
            p1 = p2;
        }

        if (counter % 2 == 0) {
            return false;
        } else {
            return true;
        }
    }
    /**
     * 判断多边形位置关系
     * @param polygon1       多边形A的实际坐标
     * @param polygon2          多边形B的实际坐标
     */
    private void getPolygonsPosition(List<Point2D> polygon1, List<Point2D> polygon2){
        //快速排除法判断存在交叉部分
        if (fastExclude(polygon1, polygon2)) {
            //点转换为线段
            List<Line2D> borderLine = point2Line(polygon1);
            List<Line2D> obLine = point2Line(polygon2);
            //跨立算法判断线段相交
            if (judgeIntersect(obLine, borderLine)) {
                //2个多边形相交
            } else {
                //2个多变形不相交
                boolean include = true;
                for (int j = 0; j < polygon2.size(); j++) {
                    //判断多边形B的点是否在多边形A的线段上
                    if (!isOnLine(borderLine, polygon2.get(j))) {
                        //射线算法判断多边形B点的是否在多边形A内
                        if (isInPolygon(polygon2.get(j), polygon1)) {
                            //多边形B在多边形A的内部（内切、内包含）
                            include = false;
                            break;
                        } else {//（外离、外包含）
                            if (isInPolygon(polygon1.get(0), polygon2)){
                                //多边形B包含多边形A
                                include = false;
                                break;
                            } else {
                                //多边形B在多边形A外部
                                include = false;
                                break;
                            }
                        }
                    }
                }
                if (include) {
                    //两个多边形重合
                }
            }
        }else{
            //两个多边形相离
        }
    }

    /**
     * 快速排除两个地块是否有交叉
     * @param obPointList   障碍区地块坐标点（XY坐标系）
     * @param pointList     边界地块坐标点（XY坐标系）
     * @return              不存在交叉则返回false
     */
    public static boolean fastExclude(List<Point2D> obPointList , List<Point2D> pointList){
        double obPointMaxX = Double.MAX_VALUE;
        double obPointMaxY = Double.MAX_VALUE;
        double obPointMinX = Double.MIN_VALUE;
        double obPointMinY = Double.MIN_VALUE;

        double pointMaxX = Double.MAX_VALUE;
        double pointMaxY = Double.MAX_VALUE;
        double pointMinX = Double.MIN_VALUE;
        double pointMinY = Double.MIN_VALUE;

        for (int i = 0; i<  obPointList.size() ;i++){
            Point2D point = obPointList.get(i);

            if (obPointMaxX == Double.MAX_VALUE) {
                obPointMaxX = point.x;
            } else if (obPointMaxX < point.x) {
                obPointMaxX = point.x;
            }

            if (obPointMaxY == Double.MAX_VALUE) {
                obPointMaxY = point.y;
            } else if (obPointMaxY < point.y) {
                obPointMaxY = point.y;
            }

            if (obPointMinX == Double.MIN_VALUE) {
                obPointMinX = point.x;
            } else if (obPointMinX > point.x) {
                obPointMinX = point.x;
            }

            if (obPointMinY == Double.MIN_VALUE) {
                obPointMinY = point.y;
            } else if (obPointMinY > point.y) {
                obPointMinY = point.y;
            }
        }

        for (int i = 0; i<  pointList.size() ;i++){
            Point2D point = pointList.get(i);

            if (pointMaxX == Double.MAX_VALUE) {
                pointMaxX = point.x;
            } else if (pointMaxX < point.x) {
                pointMaxX = point.x;
            }

            if (pointMaxY == Double.MAX_VALUE) {
                pointMaxY = point.y;
            } else if (pointMaxY < point.y) {
                pointMaxY = point.y;
            }

            if (pointMinX == Double.MIN_VALUE) {
                pointMinX = point.x;
            } else if (pointMinX > point.x) {
                pointMinX = point.x;
            }

            if (pointMinY == Double.MIN_VALUE) {
                pointMinY = point.y;
            } else if (pointMinY > point.y) {
                pointMinY = point.y;
            }
        }
        return !(obPointMaxX <= pointMinX) && !(obPointMinX >= pointMaxX) && !(obPointMaxY <= pointMinY) && !(obPointMinY >= pointMaxY);
    }

    /**
     * 跨立算法，判断线与线是否相交（不包含点边重合和边边重合）
     * 有向量 a，b，c
     * 若 (a*b)*(b*c) = 0 则两线段重合
     * 若 (a*b)*(b*c) < 0 则两线段相交
     * 若 (a*b)*(b*c) > 0 则两线段不相交
     *
     * @param obLineList    障碍区组成的线段
     * @param lineList      边界点组成的线段
     * @return              返回true则证明相交
     */
    public static boolean judgeIntersect(List<Line2D> obLineList, List<Line2D> lineList) {
        for (int i = 0; i < obLineList.size(); i++) {
            Line2D obLine = obLineList.get(i);
            for (int j = 0; j < lineList.size(); j++) {
                Vector2D vector1 = new Vector2D(obLine.startPoint.x - lineList.get(j).startPoint.x,
                        obLine.startPoint.y - lineList.get(j).startPoint.y);
                Vector2D vector2 = new Vector2D(obLine.endPoint.x - lineList.get(j).startPoint.x,
                        obLine.endPoint.y - lineList.get(j).startPoint.y);
                Vector2D vector3 = new Vector2D(lineList.get(j).endPoint.x - lineList.get(j).startPoint.x,
                        lineList.get(j).endPoint.y - lineList.get(j).startPoint.y);
                //向量vector1 与 vector3的叉乘
                double val1 = vector3.crossProduct(vector1);
                //向量vector2 与 vector3的叉乘
                double val2 = vector3.crossProduct(vector2);

                Vector2D vector4 = new Vector2D(lineList.get(j).startPoint.x - obLine.startPoint.x,
                        lineList.get(j).startPoint.y - obLine.startPoint.y);
                Vector2D vector5 = new Vector2D(lineList.get(j).endPoint.x - obLine.startPoint.x,
                        lineList.get(j).endPoint.y - obLine.startPoint.y);
                Vector2D vector6 = new Vector2D(obLine.endPoint.x - obLine.startPoint.x,
                        obLine.endPoint.y - obLine.startPoint.y);
                //向量vector4 与 vector6的叉乘
                double val3 = vector6.crossProduct(vector4);
                //向量vector5 与 vector6的叉乘
                double val4 = vector6.crossProduct(vector5);

                if (val1 * val2 < 0 && val3 * val4 < 0) {
                    return true;
                }
            }
        }
        return false;
    }
}
